package com.example.demo.taskSchedule;

import com.example.demo.DBServer.thisDatabase.service.ExecuteInformationService;
import com.example.demo.entity.ExecuteInformationEntity;
import com.example.demo.exception.BizErrorCode;
import com.example.demo.exception.BizException;
import com.example.demo.executor.Executor;
import com.example.demo.typeEnums.LoopType;
import com.example.demo.utils.TimeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Map;
import java.util.concurrent.*;

@Component
public class DataProcessSchedule{

    private ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1);

    public Map<String,DataScheduledResult> map = new ConcurrentHashMap<>();

    @Autowired
    @Qualifier("mainTableExecutor")
    private Executor executor;

    @Autowired
    private ExecuteInformationService executeInformationService;

    @Transactional(rollbackFor = Exception.class)
    public synchronized boolean schedule(ExecuteInformationEntity executeInformation){
        String tableName = executeInformation.getTableName();
        if(map.containsKey(tableName)){
            DataScheduledResult scheduledResult = map.get(tableName);
            ScheduledFuture scheduledFuture = scheduledResult.getScheduledFuture();
            if(!scheduledFuture.isCancelled() && !scheduledFuture.isDone()) {
                throw new BizException(BizErrorCode.TABLE_HAS_EXIST_DATA_PROCESS_TASK);
            }
        }

        // 保存到数据库中
        executeInformationService.saveExecuteInformation(executeInformation);

        Date startTime = executeInformation.getStartTime();
        Long initialDelay = startTime.getTime()-System.currentTimeMillis();
        if(initialDelay < 0){
            throw new BizException(BizErrorCode.HAS_BEEN_PASSED_START_EXECUTE_TIME);
        }
        // 得到循环间隔时间
        Long delay = TimeUtil.getDelayNum(executeInformation.getLoopInterval(),executeInformation.getLoopType());
        DataProcessTask  dataProcessTask = new DataProcessTask(executeInformation, executor);
        ScheduledFuture<?> scheduledFuture;
        if(delay == 0){
            scheduledFuture = executorService.schedule(dataProcessTask, initialDelay, TimeUnit.MILLISECONDS);
        }else {
            scheduledFuture = executorService.scheduleWithFixedDelay(dataProcessTask, initialDelay, delay, TimeUnit.MILLISECONDS);
        }
        DataScheduledResult scheduledResult = new DataScheduledResult(executeInformation,scheduledFuture);
        map.put(executeInformation.getTableName(),scheduledResult);
        return true;
    }

    public synchronized ExecuteInformationEntity cancelDataProcessTask(String tableName){
        if(map.containsKey(tableName)){
            DataScheduledResult scheduledResult = map.get(tableName);
            ScheduledFuture scheduledFuture = scheduledResult.getScheduledFuture();
            if(scheduledFuture.isDone()){
                throw new BizException(BizErrorCode.TABLE_TASK_HAS_BEEN_FINISHED);
            }
            if(scheduledFuture.isCancelled()){
                throw new BizException(BizErrorCode.TABLE_TASK_HAS_BEEN_CANCELED);
            }
            if(!scheduledFuture.cancel(true)){
                throw new BizException(BizErrorCode.TABLE_TASK_CANCEL_FAIL);
            }
            map.remove(tableName);
            return scheduledResult.getExecuteInformation();
        }else{
            throw new BizException(BizErrorCode.TABLE_TASK_DO_NOT_EXIST);
        }
    }
}
